#pragma once

#include <iostream>
#include <string>
#include <sstream>
#include <mutex>

#include <time.h>
#include <stdio.h>
#include <pthread.h>

#define Logi(fmt, ...) {time_t timep; time(&timep); struct tm *p = localtime(&timep); printf("%4d-%02d-%02d %02d:%02d:%02d [%llu][I] ", 1900+p->tm_year, 1+p->tm_mon, p->tm_mday, p-> tm_hour, p->tm_min, p->tm_sec, (unsigned long long)pthread_self());printf(fmt, ##__VA_ARGS__);printf("\n");fflush(stdout);}
#define Logw(fmt, ...) {time_t timep; time(&timep); struct tm *p = localtime(&timep); printf("%4d-%02d-%02d %02d:%02d:%02d [%llu][W] ", 1900+p->tm_year, 1+p->tm_mon, p->tm_mday, p-> tm_hour, p->tm_min, p->tm_sec, (unsigned long long)pthread_self());printf(fmt, ##__VA_ARGS__);printf("\n");fflush(stdout);}
#define Loge(fmt, ...) {time_t timep; time(&timep); struct tm *p = localtime(&timep); printf("%4d-%02d-%02d %02d:%02d:%02d [%llu][E] ", 1900+p->tm_year, 1+p->tm_mon, p->tm_mday, p-> tm_hour, p->tm_min, p->tm_sec, (unsigned long long)pthread_self());printf(fmt, ##__VA_ARGS__);printf("\n");fflush(stdout);}

#define W_Logi(logData) WLogi() << logData;
#define W_Logw(logData) WLogw() << logData;
#define W_Loge(logData) WLoge() << logData;

class WLog
{
public:
    enum LogLevel
    {
        ERROR,
        WARNING,
        INFO,
        DEBUG
    };

    WLog();
    virtual ~WLog();

    template<typename T>
    WLog &operator<<(const T& message)
    {
        if (_level <= s_currentLogLevel)
        {
            _logStream << message;
        }
        return *this;
    }

    static void setLogLevel(LogLevel level);
    static LogLevel getLogLevel();
    static std::string logLevelToString(LogLevel level);
    static void log(LogLevel level, const std::string& message);

protected:
    LogLevel _level = WLog::INFO;
    std::ostringstream _logStream;

    static LogLevel s_currentLogLevel;
};

class WLogd: public WLog
{
public:
    WLogd(){_level = WLog::DEBUG;}
    virtual ~WLogd() {}
};

class WLogi: public WLog
{
public:
    WLogi(){_level = WLog::INFO;}
    virtual ~WLogi() {}
};

class WLogw: public WLog
{
public:
    WLogw(){_level = WLog::WARNING;}
    virtual ~WLogw() {}
};

class WLoge: public WLog
{
public:
    WLoge(){_level = WLog::ERROR;}
    virtual ~WLoge() {}
};


